home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ghostview / misc.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  42KB  |  1,484 lines

  1. /*
  2.  * misc.c -- Everything that isn't a callback or action.
  3.  * Copyright (C) 1992  Timothy O. Theisen
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *   Author: Tim Theisen           Systems Programmer
  20.  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
  21.  *     UUCP: uwvax!tim             University of Wisconsin-Madison
  22.  *    Phone: (608)262-0438         1210 West Dayton Street
  23.  *      FAX: (608)262-9777         Madison, WI   53706
  24.  */
  25.  
  26. #include <stdio.h>
  27. #ifndef SEEK_SET
  28. #define SEEK_SET 0
  29. #endif
  30.  
  31. #include <X11/Xos.h>
  32. #include <signal.h>
  33. #ifdef SIGNALRETURNSINT
  34. #define SIGVAL int
  35. #else
  36. #define SIGVAL void
  37. #endif
  38.  
  39. #include <math.h>
  40.  
  41. #include <X11/Xatom.h>
  42. #include <X11/Intrinsic.h>
  43. #include <X11/StringDefs.h>
  44. #include <X11/Shell.h>
  45. #include <X11/Xaw/Cardinals.h>
  46. #include <X11/Xaw/Form.h>
  47. #include <X11/Xaw/SimpleMenu.h>
  48. #include <X11/Xaw/SmeBSB.h>
  49. #include <X11/Xaw/SmeLine.h>
  50. #include <X11/Xaw/Scrollbar.h>
  51. #include <X11/Xaw/AsciiText.h>
  52. /* Yuck, cannot get vScrollbar via the usual methods */
  53. #include <X11/IntrinsicP.h>
  54. #include <X11/Xaw/TextP.h>
  55. #include <X11/Xmu/StdCmap.h>
  56.  
  57. #include <errno.h>
  58. /* BSD 4.3 errno.h does not declare errno */
  59. extern int errno;
  60. #ifdef VMS
  61. #include <perror.h>
  62. #else
  63. extern int sys_nerr;
  64. extern char *sys_errlist[];
  65. #endif
  66.  
  67. #include "Ghostview.h"
  68. #include "gv.h"
  69. #include "ps.h"
  70.  
  71. #ifndef max
  72. #define max(a, b)    ((a) > (b) ? (a) : (b))
  73. #endif
  74.  
  75. /* Translate orientations defined by the enum in "ps.h" to
  76.  * XtPageOrientations defined in "Ghostview.h".
  77.  */
  78. static XtPageOrientation
  79. xorient(psorient)
  80.     int psorient;
  81. {
  82.     switch (psorient) {
  83.     case PORTRAIT: return XtPageOrientationPortrait;
  84.     case LANDSCAPE:
  85.     if (app_res.swap_landscape) {
  86.         return XtPageOrientationSeascape;
  87.     } else {
  88.         return XtPageOrientationLandscape;
  89.     }
  90.     }
  91. }
  92.  
  93. static void
  94. break_chains()
  95. {
  96.     Arg args[2];
  97.     XtSetArg(args[0], XtNbottom, XtChainTop);
  98.     XtSetArg(args[1], XtNright, XtChainLeft);
  99.     XtSetValues(toc, args, ONE);
  100.     XtSetValues(pageview, args, TWO);
  101. }
  102.  
  103. static void
  104. set_chains()
  105. {
  106.     Arg args[2];
  107.  
  108.     XtSetArg(args[0], XtNbottom, XtChainBottom);
  109.     XtSetArg(args[1], XtNright, XtChainRight);
  110.     XtSetValues(toc, args, ONE);
  111.     XtSetValues(pageview, args, TWO);
  112. }
  113.  
  114. static void
  115. reset_size_hints()
  116. {
  117.     Arg args[4];
  118.     if (app_res.ncdwm) return;
  119.     XtSetArg(args[0], XtNmaxWidth, XtUnspecifiedShellInt);
  120.     XtSetArg(args[1], XtNmaxHeight, XtUnspecifiedShellInt);
  121.     XtSetArg(args[2], XtNminWidth, XtUnspecifiedShellInt);
  122.     XtSetArg(args[3], XtNminHeight, XtUnspecifiedShellInt);
  123.     XtSetValues(toplevel, args, FOUR);
  124. }
  125.  
  126. static void
  127. set_size_hints(minw, minh, maxw, maxh)
  128.     Dimension minw, minh, maxw, maxh;
  129. {
  130.     Arg args[4];
  131.  
  132.     XtSetArg(args[0], XtNminWidth, minw);
  133.     XtSetArg(args[1], XtNminHeight, minh);
  134.     XtSetArg(args[2], XtNmaxWidth, maxw);
  135.     XtSetArg(args[3], XtNmaxHeight, maxh);
  136.     XtSetValues(toplevel, args, FOUR);
  137. }
  138.  
  139. static Boolean horiz_scroll_saved = False;
  140. static Boolean vert_scroll_saved = False;
  141. static float horiz_top;
  142. static float vert_top;
  143.  
  144. static void
  145. reset_scroll_bars()
  146. {
  147.     Arg args[1];
  148.     Widget scroll;
  149.     float zero = 0.0;
  150.     
  151.     if (horiz_scroll_saved || vert_scroll_saved) return;
  152.  
  153.     scroll = XtNameToWidget(pageview, "horizontal");
  154.     if (scroll) {
  155.     XtSetArg(args[0], XtNtopOfThumb, &horiz_top);
  156.     XtGetValues(scroll, args, ONE);
  157.     XtCallCallbacks(scroll, XtNjumpProc, &zero);
  158.     horiz_scroll_saved = True;
  159.     }
  160.  
  161.     scroll = XtNameToWidget(pageview, "vertical");
  162.     if (scroll) {
  163.     XtSetArg(args[0], XtNtopOfThumb, &vert_top);
  164.     XtGetValues(scroll, args, ONE);
  165.     XtCallCallbacks(scroll, XtNjumpProc, &zero);
  166.     vert_scroll_saved = True;
  167.     }
  168. }
  169.  
  170. static void
  171. set_scroll_bars()
  172. {
  173.     Arg args[1];
  174.     Widget scroll;
  175.     float shown;
  176.  
  177.     if (horiz_scroll_saved) {
  178.     scroll = XtNameToWidget(pageview, "horizontal");
  179.     if (scroll) {
  180.         XtSetArg(args[0], XtNshown, &shown);
  181.         XtGetValues(scroll, args, ONE);
  182.         if (horiz_top > (1.0 - shown)) horiz_top = (1.0 - shown);
  183.         XtCallCallbacks(scroll, XtNjumpProc, &horiz_top);
  184.     }
  185.     }
  186.  
  187.     if (vert_scroll_saved) {
  188.     scroll = XtNameToWidget(pageview, "vertical");
  189.     if (scroll) {
  190.         XtSetArg(args[0], XtNshown, &shown);
  191.         XtGetValues(scroll, args, ONE);
  192.         if (vert_top > (1.0 - shown)) vert_top = (1.0 - shown);
  193.         XtCallCallbacks(scroll, XtNjumpProc, &vert_top);
  194.     }
  195.     }
  196.  
  197.     horiz_scroll_saved = vert_scroll_saved = False;
  198. }
  199.  
  200. /* Start rendering a new page */
  201. void
  202. show_page(number)
  203.     int number;
  204. {
  205.     struct stat sbuf;
  206.     int i;
  207.  
  208.     if (!filename) return;
  209.  
  210.     /* Unmark current_page as current */
  211.     if (toc_text && (current_page >= 0)) {
  212.     int marker = current_page*toc_entry_length + toc_entry_length-2;
  213.     toc_text[marker] = ' ';
  214.     XawTextInvalidate(toc, marker, marker+1);
  215.     }
  216.  
  217.     /* If the file has changed, rescan it so that offsets into the file
  218.      * are still correct.  If the file is rescanned, we must setup ghostview
  219.      * again.  Also, force a new copy of ghostscript to start. */
  220.     if (psfile) {
  221.     if (!stat(filename, &sbuf) && mtime != sbuf.st_mtime) {
  222.         fclose(psfile);
  223.         psfile = fopen(filename, "r");
  224.         mtime = sbuf.st_mtime;
  225.         if (oldfilename) XtFree(oldfilename);
  226.         oldfilename = XtNewString(filename);
  227.         new_file(number);
  228.     }
  229.     }
  230.  
  231.     /* Coerce page number to fall in range */
  232.     if (toc_text) {
  233.     if (number >= doc->numpages) number = doc->numpages - 1;
  234.     if (number < 0) number = 0;
  235.     }
  236.  
  237.     if (set_new_orientation(number) || set_new_pagemedia(number))
  238.     layout_ghostview();
  239.  
  240.     if (toc_text) {
  241.     int marker;
  242.     current_page = number;
  243.     XawTextUnsetSelection(toc);
  244.     XawTextSetInsertionPoint(toc, current_page * toc_entry_length);
  245.     marker = current_page*toc_entry_length + toc_entry_length-2;
  246.     toc_text[marker] = '<';
  247.     XawTextInvalidate(toc, marker, marker+1);
  248.     if (GhostviewIsInterpreterReady(page)) {
  249.         GhostviewNextPage(page);
  250.     } else {
  251.         GhostviewEnableInterpreter(page);
  252.         GhostviewSendPS(page, psfile, doc->beginprolog,
  253.                 doc->lenprolog, False);
  254.         GhostviewSendPS(page, psfile, doc->beginsetup,
  255.                 doc->lensetup, False);
  256.     }
  257.     if (doc->pageorder == DESCEND)
  258.         i = (doc->numpages - 1) - current_page;
  259.     else
  260.         i = current_page;
  261.     GhostviewSendPS(page, psfile, doc->pages[i].begin,
  262.             doc->pages[i].len, False);
  263.     } else {
  264.     if (!GhostviewIsInterpreterRunning(page))
  265.         GhostviewEnableInterpreter(page);
  266.     else if (GhostviewIsInterpreterReady(page))
  267.         GhostviewNextPage(page);
  268.     else
  269.         XBell(XtDisplay(page), 0);
  270.     }
  271.  
  272.     if (toc_text) {
  273.     XtSetSensitive(prevbutton, current_page != 0);
  274.     XtSetSensitive(nextbutton, current_page != doc->numpages-1);
  275.     XtSetSensitive(showbutton, True);
  276.     }
  277. }
  278.  
  279. /* setup ghostview.  This includes:
  280.  *  scanning the PostScript file,
  281.  *  setting the title and date labels,
  282.  *  building the pagemedia menu,
  283.  *  building the toc (table of contents)
  284.  *  sensitizing the appropriate menu buttons,
  285.  *  popping down and erasing the infotext popup.
  286.  */
  287.  
  288. static Boolean useful_page_labels;
  289. Boolean
  290. setup_ghostview()
  291. {
  292.     Arg args[20];
  293.     Cardinal num_args;
  294.     int oldtoc_entry_length;
  295.     char *tocp;
  296.     XawTextBlock message_block;
  297.     static String nothing = "";
  298.     String label;
  299.     Pixmap bitmap;
  300.  
  301.     /* Reset to a known state. */
  302.     psfree(olddoc);
  303.     olddoc = doc;
  304.     doc = NULL;
  305.     current_page = -1;
  306.     if (toc_text) XtFree(toc_text);
  307.     oldtoc_entry_length = toc_entry_length;
  308.     toc_text = NULL;
  309.  
  310.     /* Scan document and start setting things up */
  311.     if (psfile) doc = psscan(psfile);
  312.  
  313.     if (app_res.show_title) {
  314.     if (doc && doc->title) {
  315.         label = doc->title;
  316.         bitmap = menu16_bitmap;
  317.     } else {
  318.         if (filename) {
  319.         label = filename;
  320.         } else {
  321.         label = "";
  322.         }
  323.         bitmap = None;
  324.     }
  325.     XtSetArg(args[0], XtNlabel, label);
  326.     XtSetValues(titlebutton, args, ONE);
  327.     if (titlemenu) XtDestroyWidget(titlemenu);
  328.     titlemenu = build_label_menu(titlebutton, "title", label, bitmap);
  329.     }
  330.  
  331.     if (app_res.show_date) {
  332.     if (doc && doc->date) {
  333.         label = doc->date;
  334.         bitmap = menu16_bitmap;
  335.     } else {
  336.         if (psfile) {
  337.         label = ctime(&mtime);
  338.         } else {
  339.         label = "";
  340.         }
  341.         bitmap = None;
  342.     }
  343.     XtSetArg(args[0], XtNlabel, label);
  344.     XtSetValues(datebutton, args, ONE);
  345.     if (datemenu) XtDestroyWidget(datemenu);
  346.     datemenu = build_label_menu(datebutton, "date", label, bitmap);
  347.     }
  348.  
  349.     build_pagemedia_menu();
  350.  
  351.     /* Reset ghostscript and output messages popup */
  352.     if (!doc || !olddoc ||
  353.     strcmp(oldfilename, filename) ||
  354.     olddoc->beginprolog != doc->beginprolog ||
  355.     olddoc->endprolog != doc->endprolog ||
  356.     olddoc->beginsetup != doc->beginsetup ||
  357.     olddoc->endsetup != doc->endsetup) {
  358.  
  359.     GhostviewDisableInterpreter(page);
  360.     XtPopdown(infopopup);
  361.     info_up = False;
  362.     XtSetArg(args[0], XtNeditType, XawtextEdit);
  363.     XtSetArg(args[1], XtNinsertPosition, 0);
  364.     XtSetValues(infotext, args, TWO);
  365.     message_block.length = 0;
  366.     XawTextReplace(infotext, 0, info_length, &message_block);
  367.     info_length = 0;
  368.     XtSetArg(args[0], XtNeditType, XawtextRead);
  369.     XtSetValues(infotext, args, ONE);
  370.     }
  371.  
  372.     /* Build table of contents */
  373.     if (doc && (!doc->epsf && doc->numpages > 0 ||
  374.          doc->epsf && doc->numpages > 1)) {
  375.     int maxlen = 0;
  376.     int i, j;
  377.     useful_page_labels = False;
  378.  
  379.     if (doc->numpages == 1) useful_page_labels = True;
  380.     for (i = 1; i < doc->numpages; i++)
  381.         if (useful_page_labels = (useful_page_labels ||
  382.             strcmp(doc->pages[i-1].label, doc->pages[i].label))) break;
  383.     if (useful_page_labels) {
  384.         for (i = 0; i < doc->numpages; i++) 
  385.         maxlen = max(maxlen, strlen(doc->pages[i].label));
  386.     } else {
  387.         double x;
  388.         x = doc->numpages;
  389.         maxlen = log10(x) + 1;
  390.     }
  391.     toc_entry_length = maxlen + 3;
  392.     toc_length = doc->numpages * toc_entry_length - 1;
  393.     toc_text = XtMalloc(toc_length + 2); /* include final NULL */
  394.  
  395.     for (i = 0, tocp = toc_text; i < doc->numpages;
  396.          i++, tocp += toc_entry_length) {
  397.         if (useful_page_labels) {
  398.         if (doc->pageorder == DESCEND) {
  399.             j = (doc->numpages - 1) - i;
  400.         } else {
  401.             j = i;
  402.         }
  403.         sprintf(tocp, " %*s \n", maxlen, doc->pages[j].label);
  404.         } else {
  405.         sprintf(tocp, " %*d \n", maxlen, i+1);
  406.         }
  407.     }
  408.     toc_text[toc_length] = '\0';
  409.                                       num_args = 0;
  410.     XtSetArg(args[num_args], XtNfilename, NULL);          num_args++;
  411.     XtSetValues(page, args, num_args);
  412.     } else {
  413.     toc_length = 0;
  414.     toc_entry_length = 3;
  415.                                       num_args = 0;
  416.     XtSetArg(args[num_args], XtNfilename, filename);          num_args++;
  417.     XtSetValues(page, args, num_args);
  418.     }
  419.                                 num_args = 0;
  420.     XtSetArg(args[num_args], XtNlength, toc_length);        num_args++;
  421.     if (toc_text) {
  422.     XtSetArg(args[num_args], XtNstring, toc_text);        num_args++;
  423.     } else {
  424.     /* Text widget sometime blows up when given a NULL pointer */
  425.     XtSetArg(args[num_args], XtNstring, nothing);        num_args++;
  426.     }
  427.     XtSetValues(toc, args, num_args);
  428.  
  429.     XtSetSensitive(reopenbutton, (psfile != NULL));
  430.     XtSetSensitive(printwholebutton, (psfile != NULL));
  431.     XtSetSensitive(printmarkedbutton, (psfile != NULL));
  432.     XtSetSensitive(savebutton, (toc_text != NULL));
  433.     XtSetSensitive(nextbutton, (filename != NULL));
  434.     XtSetSensitive(showbutton, (filename != NULL));
  435.     XtSetSensitive(prevbutton, (toc_text != NULL));
  436.     XtSetSensitive(centerbutton, (filename != NULL));
  437.     XtSetSensitive(markbutton, (toc_text != NULL));
  438.     XtSetSensitive(unmarkbutton, (toc_text != NULL));
  439.  
  440.     return oldtoc_entry_length != toc_entry_length;
  441. }
  442.  
  443. int
  444. find_page(label)
  445.     String label;
  446. {
  447.     int i, j;
  448.  
  449.     if (label == NULL || doc == NULL) return 0;
  450.  
  451.     if (useful_page_labels) {
  452.     for (i = 0; i < doc->numpages; i++) {
  453.         if (doc->pageorder == DESCEND) {
  454.         j = (doc->numpages - 1) - i;
  455.         } else {
  456.         j = i;
  457.         }
  458.         if (!strcmp(label, doc->pages[j].label)) return i;
  459.     }
  460.     return 0;
  461.     } else {
  462.     return atoi(label) - 1;
  463.     }
  464. }
  465.  
  466. /* try_try_again sets the geometry of the form when the form failed
  467.  * to do it earlier.  It uses activity check with exponential backoff
  468.  * to make sure that the dust has settled before trying again.
  469.  */
  470. static unsigned int delay = 125;    /* Start with 1/8 second delay */
  471.  
  472. static void
  473. try_try_again(client_data, timer)
  474.     XtPointer client_data;
  475.     XtIntervalId *timer;
  476. {
  477.     XSync(XtDisplay(toplevel), False);    /* Push everything out */
  478.     if (XtAppPending(app_con)) {
  479.     XtAppAddTimeOut(app_con, delay, try_try_again, NULL);
  480.     /* fprintf(stderr, "Delaying(%d)...\n",delay); */
  481.     delay *= 2;
  482.     } else {
  483.     /* fprintf(stderr, "Trying again...\n"); */
  484.     layout_ghostview();
  485.     }
  486. }
  487.  
  488. /* set the dimensions for items in the main form widget. */
  489. /* set foreground and background color in scrollbars. */
  490. /* (The scroll bars come and go as size changes.) */
  491. /* Set window manager hints to keep window manager from causing main */
  492. /* viewport from growing too large */
  493. void
  494. layout_ghostview()
  495. {
  496.     Arg args[20];
  497.     Cardinal num_args;
  498.     Widget w;
  499.     /* Yuck, cannot get vScrollbar via the usual methods */
  500.     TextWidget tw;
  501.     Dimension min_width, min_height;
  502.     Dimension max_width, max_height;
  503.     Dimension form_width, form_height;
  504.     Dimension title_height, title_border;
  505.     Dimension date_height, date_border;
  506.     Dimension locator_height, locator_border;
  507.     Dimension box_width, box_height, box_border;
  508.     Dimension label_width;
  509.     Dimension toc_width, toc_height, toc_border;
  510.     Dimension view_width, view_height, view_border;
  511.     Dimension page_width, page_height;
  512.     Dimension leftMargin, rightMargin;
  513.     Dimension width, height;
  514.     Boolean correct = True;
  515.     int distance;
  516.     int a_label;
  517.     XFontStruct *font;
  518.  
  519.     XawFormDoLayout(form, False);
  520.     reset_size_hints();
  521.     reset_scroll_bars();
  522.     break_chains();
  523.  
  524.     XtSetArg(args[0], XtNdefaultDistance, &distance);
  525.     XtGetValues(form, args, ONE);
  526.  
  527.     a_label = 0;
  528.     if (app_res.show_title) {
  529.     XtSetArg(args[0], XtNheight, &title_height);
  530.     XtSetArg(args[1], XtNborderWidth, &title_border);
  531.     XtGetValues(titlebutton, args, TWO);
  532.     a_label = 1;
  533.     } else {
  534.     title_height = title_border = 0;
  535.     }
  536.  
  537.     if (app_res.show_date) {
  538.     XtSetArg(args[0], XtNheight, &date_height);
  539.     XtSetArg(args[1], XtNborderWidth, &date_border);
  540.     XtGetValues(datebutton, args, TWO);
  541.     a_label = 1;
  542.     } else {
  543.     date_height = date_border = 0;
  544.     }
  545.  
  546.     if (app_res.show_locator) {
  547.     XtSetArg(args[0], XtNheight, &locator_height);
  548.     XtSetArg(args[1], XtNborderWidth, &locator_border);
  549.     XtGetValues(locator, args, TWO);
  550.     a_label = 1;
  551.     } else {
  552.     locator_height = locator_border = 0;
  553.     }
  554.  
  555.     XtSetArg(args[0], XtNwidth, &box_width);
  556.     XtSetArg(args[1], XtNheight, &box_height);
  557.     XtSetArg(args[2], XtNborderWidth, &box_border);
  558.     XtGetValues(box, args, THREE);
  559.  
  560.     XtSetArg(args[0], XtNfont, &font);
  561.     XtSetArg(args[1], XtNleftMargin, &leftMargin);
  562.     XtSetArg(args[2], XtNrightMargin, &rightMargin);
  563.     XtSetArg(args[3], XtNborderWidth, &toc_border);
  564.     XtGetValues(toc, args, FOUR);
  565.     toc_width = font->max_bounds.width * (toc_entry_length - 1) +
  566.         leftMargin + rightMargin;
  567.  
  568.     XtSetArg(args[0], XtNwidth, &page_width);
  569.     XtSetArg(args[1], XtNheight, &page_height);
  570.     XtGetValues(page, args, TWO);
  571.  
  572.     XtSetArg(args[0], XtNborderWidth, &view_border);
  573.     XtGetValues(pageview, args, ONE);
  574.     view_width = page_width;
  575.     view_height = page_height;
  576.  
  577.     min_width = box_width + 2*box_border + toc_width + 2*toc_border +
  578.         2*view_border + 4*distance;
  579.     min_height = title_height + 2*title_border + date_height + 2*date_border +
  580.          locator_height + 2*locator_border + box_height + 2*box_border +
  581.          (2+a_label)*distance;
  582.  
  583.     max_width = WidthOfScreen(XtScreen(toplevel)) - app_res.wm_horiz_margin;
  584.     max_height = HeightOfScreen(XtScreen(toplevel)) - app_res.wm_vert_margin;
  585.  
  586.     if (min_width + view_width > max_width)
  587.     view_width = max_width - min_width;
  588.     if (2*(view_border + distance) + view_height > max_height)
  589.     view_height = max_height - 2*(view_border + distance);
  590.     form_width = view_width + min_width;
  591.     form_height = max(view_height + 2*(view_border + distance), min_height);
  592.     toc_height = view_height - (title_height + 2*title_border +
  593.                 date_height + 2*date_border +
  594.                 locator_height + 2*locator_border +
  595.                 a_label*distance);
  596.  
  597.     label_width = box_width + 2*box_border + distance +
  598.           toc_width + 2*toc_border;
  599.  
  600.     XtSetArg(args[0], XtNwidth, form_width);
  601.     XtSetArg(args[1], XtNheight, form_height);
  602.     XtSetValues(form, args, TWO);
  603.  
  604.     XtSetArg(args[0], XtNwidth, label_width);
  605.     if (app_res.show_title) XtSetValues(titlebutton, args, ONE);
  606.     if (app_res.show_date) XtSetValues(datebutton, args, ONE);
  607.     if (app_res.show_locator) XtSetValues(locator, args, ONE);
  608.  
  609.     XtSetArg(args[0], XtNwidth, toc_width);
  610.     XtSetArg(args[1], XtNheight, toc_height);
  611.     XtSetValues(toc, args, TWO);
  612.  
  613.     XtSetArg(args[0], XtNwidth, view_width);
  614.     XtSetArg(args[1], XtNheight, view_height);
  615.     XtSetValues(pageview, args, TWO);
  616.  
  617.     XawFormDoLayout(form, True);
  618.  
  619.     /* Check to make sure everything was done as planned. */
  620.     XtSetArg(args[0], XtNwidth, &width);
  621.     XtSetArg(args[1], XtNheight, &height);
  622.  
  623.     XtGetValues(form, args, TWO);
  624.     if (width != form_width || height != form_height) {
  625.     correct = False;
  626.     /* fprintf(stderr, "Oops, %dx%d form was supposed to be %dx%d.\n",
  627.         width, height, form_width, form_height); */
  628.     }
  629.     if (app_res.show_title) {
  630.     XtGetValues(titlebutton, args, ONE);
  631.     if (width != label_width) {
  632.         correct = False;
  633.         /* fprintf(stderr,
  634.         "Oops, %d wide title was supposed to be %d wide.\n",
  635.         width, label_width); */
  636.     }
  637.     }
  638.     if (app_res.show_date) {
  639.     XtGetValues(datebutton, args, ONE);
  640.     if (width != label_width) {
  641.         correct = False;
  642.         /* fprintf(stderr,
  643.         "Oops, %d wide date was supposed to be %d wide.\n",
  644.         width, label_width); */
  645.     }
  646.     }
  647.     if (app_res.show_locator) {
  648.     XtGetValues(locator, args, ONE);
  649.     if (width != label_width) {
  650.         correct = False;
  651.         /* fprintf(stderr,
  652.         "Oops, %d wide locator was supposed to be %d wide.\n",
  653.         width, label_width); */
  654.     }
  655.     }
  656.     XtGetValues(toc, args, TWO);
  657.     if (width != toc_width || height != toc_height) {
  658.     correct = False;
  659.     /* fprintf(stderr, "Oops, %dx%d toc was supposed to be %dx%d.\n",
  660.         width, height, toc_width, toc_height); */
  661.     }
  662.     XtGetValues(pageview, args, TWO);
  663.     if (width != view_width || height != view_height) {
  664.     correct = False;
  665.     /* fprintf(stderr, "Oops, %dx%d pageview was supposed to be %dx%d.\n",
  666.         width, height, view_width, view_height); */
  667.     }
  668.  
  669.     if (correct) {
  670.     if (special_cmap) {
  671.         /* Yuck, cannot get vScrollbar via the usual methods */
  672.         /* w = XtNameToWidget(toc, "*vScrollbar"); */
  673.         tw = (TextWidget) toc;
  674.         w = tw->text.vbar;
  675.         if (w) {
  676.         /* Double Yuck, have to set them twice to make them */
  677.         /* get the right colors */
  678.                                 num_args = 0;
  679.         XtSetArg(args[num_args], XtNforeground, white);    num_args++;
  680.         XtSetArg(args[num_args], XtNbackground, black);    num_args++;
  681.         XtSetValues(w, args, num_args);
  682.                                 num_args = 0;
  683.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  684.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  685.         XtSetValues(w, args, num_args);
  686.         }
  687.  
  688.         w = XtNameToWidget(pageview, "horizontal");
  689.         if (w) {
  690.                                 num_args = 0;
  691.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  692.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  693.         XtSetValues(w, args, num_args);
  694.         }
  695.  
  696.         w = XtNameToWidget(pageview, "vertical");
  697.         if (w) {
  698.                                 num_args = 0;
  699.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  700.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  701.         XtSetValues(w, args, num_args);
  702.         }
  703.     }
  704.  
  705.     set_size_hints(min_width, min_height, min_width+page_width,
  706.                max(form_height,
  707.                page_height + 2*(view_border + distance)));
  708.     if (app_res.auto_center) {
  709.         horiz_scroll_saved = vert_scroll_saved = False;
  710.         center_page(form, NULL, NULL);
  711.     } else {
  712.         set_scroll_bars();
  713.     }
  714.     set_chains();
  715.     delay = 125;    /* Reset to 1/8 second delay */
  716.     /* fprintf(stderr, "Layout correct.\n"); */
  717.     } else {
  718.     XSync(XtDisplay(toplevel), False);
  719.     XtAppAddTimeOut(app_con, delay, try_try_again, NULL);
  720.     /* fprintf(stderr, "Didn't work, scheduling(%d)...\n",delay); */
  721.     }
  722.  
  723. }
  724.  
  725. /* Create a Standard colormap for ghostscript to use. */
  726. void
  727. SetStandardColormap(w)
  728.     Widget w;
  729. {
  730.     XVisualInfo xvinfo;
  731.     XVisualInfo *xvinfop;
  732.     Atom prop;
  733.     XStandardColormap *std_cmap = NULL;
  734.     XStandardColormap *scmap, *sp;
  735.     Screen *scr = DefaultScreenOfDisplay(XtDisplay(w));
  736.     int nitems, i;
  737.     Boolean has_color;
  738.     Arg args[20];
  739.     Cardinal num_args;
  740.  
  741.     XtSetArg(args[0], XtNvisual, &(xvinfo.visual));
  742.     XtGetValues(w, args, ONE);
  743.     if (xvinfo.visual == CopyFromParent)
  744.     xvinfo.visual = DefaultVisualOfScreen(scr);
  745.     xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
  746.     xvinfop = XGetVisualInfo(XtDisplay(w), VisualIDMask, &xvinfo, &nitems);
  747.     if (xvinfop == NULL) {
  748.         fprintf(stderr, "Bad visual class.\n");
  749.     exit(1);
  750.     }
  751.     xvinfo = *xvinfop;
  752.     XtFree((char *)xvinfop);
  753.  
  754.     has_color = (xvinfo.class != StaticGray) && (xvinfo.class != GrayScale);
  755.  
  756.     if (has_color) {
  757.     if (xvinfo.visual == DefaultVisualOfScreen(scr)) {
  758.         prop = XA_RGB_DEFAULT_MAP;
  759.     } else {
  760.         prop = XA_RGB_BEST_MAP;
  761.     }
  762.     } else {
  763.     prop = XA_RGB_GRAY_MAP;
  764.     }
  765.  
  766.     if (XGetRGBColormaps(XtDisplay(w), RootWindowOfScreen(scr),
  767.              &scmap, &nitems, prop)) {
  768.     for (i = 0, sp = scmap; i < nitems; i++, sp++) {
  769.         if (xvinfo.visualid == sp->visualid) {
  770.         std_cmap = sp;
  771.         break;
  772.         }
  773.     }
  774.     }
  775.  
  776.     if (!std_cmap && app_res.install_std_cmap) {
  777.     if (XmuLookupStandardColormap(XtDisplay(w),
  778.                       DefaultScreen(XtDisplay(w)),
  779.                       xvinfo.visualid, xvinfo.depth,
  780.                       prop, False, app_res.retain_std_cmap)) {
  781.         if (XGetRGBColormaps(XtDisplay(w), RootWindowOfScreen(scr),
  782.                  &scmap, &nitems, prop)) {
  783.         for (i = 0, sp = scmap; i < nitems; i++, sp++) {
  784.             if (xvinfo.visualid == sp->visualid) {
  785.             std_cmap = sp;
  786.             }
  787.         }
  788.         }
  789.     }
  790.     }
  791.  
  792.     if (std_cmap && xvinfo.visual == DefaultVisualOfScreen(scr) &&
  793.     std_cmap->colormap != DefaultColormapOfScreen(scr) &&
  794.     !app_res.private_cmap) {
  795.     std_cmap = NULL;
  796.     }
  797.     if (std_cmap) {
  798.     cmap = std_cmap->colormap;
  799.     if (std_cmap->colormap != DefaultColormapOfScreen(scr)) {
  800.         black = std_cmap->base_pixel;
  801.         white = std_cmap->red_max * std_cmap->red_mult +
  802.             std_cmap->green_max * std_cmap->green_mult +
  803.             std_cmap->blue_max * std_cmap->blue_mult +
  804.             std_cmap->base_pixel;
  805.     } else {
  806.         white = WhitePixelOfScreen(scr);
  807.         black = BlackPixelOfScreen(scr);
  808.     }
  809.     } else {
  810.     if (xvinfo.visual == DefaultVisualOfScreen(scr)) {
  811.         cmap = DefaultColormapOfScreen(scr);
  812.         white = WhitePixelOfScreen(scr);
  813.         black = BlackPixelOfScreen(scr);
  814.     } else {
  815.         XColor c;
  816.         cmap = XCreateColormap(XtDisplay(w), RootWindowOfScreen(scr),
  817.                    xvinfo.visual, AllocNone);
  818.         c.red = c.green = c.blue = ~(unsigned short)0;
  819.         XAllocColor(XtDisplay(w), cmap, &c);
  820.         white = c.pixel;
  821.         c.red = c.green = c.blue = 0;
  822.         XAllocColor(XtDisplay(w), cmap, &c);
  823.         black = c.pixel;
  824.     }
  825.     }
  826.     special_cmap = cmap != DefaultColormapOfScreen(scr);
  827.  
  828.                             num_args = 0;
  829.     XtSetArg(args[num_args], XtNcolormap, cmap);    num_args++;
  830.     if (special_cmap) {
  831.     XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  832.     XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  833.     }
  834.     XtSetValues(w, args, num_args);
  835. }
  836.  
  837. /* Compute new dpi from magstep */
  838. void
  839. magnify(dpi, magstep)
  840.     float *dpi;
  841.     int    magstep;
  842. {
  843.     if (magstep < 0) {
  844.     while (magstep++) *dpi /= 1.2;
  845.     } else {
  846.     while (magstep--) *dpi *= 1.2;
  847.     }
  848. }
  849.  
  850. /* Attempt to open file, return error message string on failure */
  851. String
  852. open_file(name)
  853.     String name;
  854. {
  855.     FILE *fp;
  856.     struct stat sbuf;
  857.  
  858.     if (*name == '\0') {    /* Null filename */
  859.     return(NULL);
  860.     }
  861.     if (strcmp(name, "-")) {
  862.     if ((fp = fopen(name, "r")) == NULL) {
  863.         String buf = XtMalloc(strlen(app_res.open_fail) +
  864.                   strlen(sys_errlist[errno]) + 1);
  865.         strcpy(buf, app_res.open_fail);
  866.         if (errno <= sys_nerr) strcat(buf, sys_errlist[errno]);
  867.         return buf;
  868.     } else {
  869.         if (oldfilename) XtFree(oldfilename);
  870.         oldfilename = filename;
  871.         filename = XtNewString(name);
  872.         if (psfile) fclose(psfile);
  873.         psfile = fp;
  874.         stat(filename, &sbuf);
  875.         mtime = sbuf.st_mtime;
  876.         new_file(0);
  877.         show_page(0);
  878.         return(NULL);
  879.     }
  880.     } else {
  881.     if (oldfilename) XtFree(oldfilename);
  882.     oldfilename = filename;
  883.     filename = XtNewString(name);
  884.     if (psfile) fclose(psfile);
  885.     psfile = NULL;
  886.     new_file(0);
  887.     show_page(0);
  888.     return(NULL);
  889.     }
  890. }
  891.  
  892. /* Attempt to save file, return error message string on failure */
  893. String
  894. save_file(name)
  895.     String name;
  896. {
  897.     FILE *pswrite;
  898.  
  899.     if (*name == '\0') {    /* Null filename */
  900.     return(NULL);
  901.     }
  902.     if ((pswrite = fopen(name, "w")) == NULL) {
  903.     String buf = XtMalloc(strlen(app_res.save_fail) +
  904.                   strlen(sys_errlist[errno]) + 1);
  905.     strcpy(buf, app_res.save_fail);
  906.     if (errno <= sys_nerr) strcat(buf, sys_errlist[errno]);
  907.     return buf;
  908.     } else {
  909.     pscopydoc(pswrite);
  910.     fclose(pswrite);
  911.     return(NULL);
  912.     }
  913. }
  914.  
  915. /* Attempt to print file.  Return error string on failure */ 
  916. String
  917. print_file(name, whole_mode)
  918.     String name;
  919.     Boolean whole_mode;
  920. {
  921.     FILE *printer;
  922.     SIGVAL (*oldsig)();
  923.     int bytes;
  924.     char buf[BUFSIZ];
  925. #ifdef VMS
  926.     char fnam[64], *p;
  927. #endif
  928.     Boolean failed;
  929.     String ret_val;
  930.  
  931. #ifdef VMS
  932.     sprintf(fnam, "sys$scratch:%s.tmp", tmpnam(NULL));
  933.     printer = fopen(fnam, "w");
  934. #else /* VMS */
  935.     if (*name != '\0') {
  936.     setenv(app_res.printer_variable, name, True);
  937.     }
  938.     oldsig = signal(SIGPIPE, SIG_IGN);
  939.     printer = popen(app_res.print_command, "w");
  940. #endif /* VMS */
  941.     if (toc_text && !whole_mode) {
  942.     pscopydoc(printer);
  943.     } else {
  944.     FILE *psfile = fopen(filename, "r");
  945.     while (bytes = read(fileno(psfile), buf, BUFSIZ))
  946.         bytes = write(fileno(printer), buf, bytes);
  947.     fclose(psfile);
  948.     }
  949. #ifdef VMS
  950.     sprintf(buf, "%s %s %s", app_res.print_command, name, fnam);
  951.     failed = fclose(printer) != 0 || system(buf) != 1;
  952. #else /* VMS */
  953.     failed = pclose(printer) != 0;
  954. #endif /* VMS */
  955.     if (failed) {
  956.     sprintf(buf, app_res.print_fail, app_res.print_command);
  957.     ret_val = XtNewString(buf);
  958.     } else {
  959.     ret_val = NULL;
  960.     }
  961. #ifndef VMS
  962.     signal(SIGPIPE, oldsig);
  963. #endif /* VMS */
  964.     return(ret_val);
  965. }
  966.  
  967. /* length calculates string length at compile time */
  968. /* can only be used with character constants */
  969. #define length(a) (sizeof(a)-1)
  970.  
  971. /* Copy the headers, marked pages, and trailer to fp */
  972. void
  973. pscopydoc(fp)
  974.     FILE *fp;
  975. {
  976.     FILE *psfile;
  977.     char text[PSLINELENGTH];
  978.     char *comment;
  979.     Boolean pages_written = False;
  980.     Boolean pages_atend = False;
  981.     Boolean marked_pages = False;
  982.     int pages = 0;
  983.     int page = 1;
  984.     int i, j;
  985.     long here;
  986.  
  987.     psfile = fopen(filename, "r");
  988.  
  989.     for (i = 0; i < doc->numpages; i++) {
  990.     if (toc_text[toc_entry_length * i] == '*') pages++;
  991.     }
  992.  
  993.     if (pages == 0) {    /* User forgot to mark the pages */
  994.     mark_page(form, NULL, NULL);
  995.     marked_pages = True;
  996.     for (i = 0; i < doc->numpages; i++) {
  997.         if (toc_text[toc_entry_length * i] == '*') pages++;
  998.     }
  999.     }
  1000.  
  1001.     here = doc->beginheader;
  1002.     while (comment = pscopyuntil(psfile, fp, here,
  1003.                  doc->endheader, "%%Pages:")) {
  1004.     here = ftell(psfile);
  1005.     if (pages_written || pages_atend) {
  1006.         free(comment);
  1007.         continue;
  1008.     }
  1009.     sscanf(comment+length("%%Pages:"), "%s", text);
  1010.     if (strcmp(text, "(atend)") == 0) {
  1011.         fputs(comment, fp);
  1012.         pages_atend = True;
  1013.     } else {
  1014.         switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  1015.         case 1:
  1016.             fprintf(fp, "%%%%Pages: %d %d\n", pages, i);
  1017.             break;
  1018.         default:
  1019.             fprintf(fp, "%%%%Pages: %d\n", pages);
  1020.             break;
  1021.         }
  1022.         pages_written = True;
  1023.     }
  1024.     free(comment);
  1025.     }
  1026.     pscopy(psfile, fp, doc->beginpreview, doc->endpreview);
  1027.     pscopy(psfile, fp, doc->begindefaults, doc->enddefaults);
  1028.     pscopy(psfile, fp, doc->beginprolog, doc->endprolog);
  1029.     pscopy(psfile, fp, doc->beginsetup, doc->endsetup);
  1030.  
  1031.     for (i = 0; i < doc->numpages; i++) {
  1032.     if (doc->pageorder == DESCEND) 
  1033.         j = (doc->numpages - 1) - i;
  1034.     else
  1035.         j = i;
  1036.     if (toc_text[toc_entry_length * j] == '*') {
  1037.         comment = pscopyuntil(psfile, fp, doc->pages[i].begin,
  1038.                   doc->pages[i].end, "%%Page:");
  1039.         fprintf(fp, "%%%%Page: %s %d\n",
  1040.             doc->pages[i].label, page++);
  1041.         free(comment);
  1042.         pscopy(psfile, fp, -1, doc->pages[i].end);
  1043.     }
  1044.     }
  1045.  
  1046.     here = doc->begintrailer;
  1047.     while (comment = pscopyuntil(psfile, fp, here,
  1048.                  doc->endtrailer, "%%Pages:")) {
  1049.     here = ftell(psfile);
  1050.     if (pages_written) {
  1051.         free(comment);
  1052.         continue;
  1053.     }
  1054.     switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  1055.         case 1:
  1056.         fprintf(fp, "%%%%Pages: %d %d\n", pages, i);
  1057.         break;
  1058.         default:
  1059.         fprintf(fp, "%%%%Pages: %d\n", pages);
  1060.         break;
  1061.     }
  1062.     pages_written = True;
  1063.     free(comment);
  1064.     }
  1065.     fclose(psfile);
  1066.  
  1067.     if (marked_pages) unmark_page(form, NULL, NULL);
  1068. }
  1069. #undef length
  1070.  
  1071. /* position popup window under the cursor */
  1072. void
  1073. positionpopup(w)
  1074.     Widget w;
  1075. {
  1076.     Arg args[3];
  1077.     Cardinal num_args;
  1078.     Dimension width, height, b_width;
  1079.     int x, y, max_x, max_y;
  1080.     Window root, child;
  1081.     int dummyx, dummyy;
  1082.     unsigned int dummymask;
  1083.     
  1084.     XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
  1085.           &dummyx, &dummyy, &dummymask);
  1086.     num_args = 0;
  1087.     XtSetArg(args[num_args], XtNwidth, &width); num_args++;
  1088.     XtSetArg(args[num_args], XtNheight, &height); num_args++;
  1089.     XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
  1090.     XtGetValues(w, args, num_args);
  1091.  
  1092.     width += 2 * b_width;
  1093.     height += 2 * b_width;
  1094.  
  1095.     x -= ( (Position) width/2 );
  1096.     if (x < 0) x = 0;
  1097.     if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
  1098.  
  1099.     y -= ( (Position) height/2 );
  1100.     if (y < 0) y = 0;
  1101.     if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
  1102.     
  1103.     num_args = 0;
  1104.     XtSetArg(args[num_args], XtNx, x); num_args++;
  1105.     XtSetArg(args[num_args], XtNy, y); num_args++;
  1106.     XtSetValues(w, args, num_args);
  1107. }
  1108.  
  1109. /* Set new magstep */
  1110. Boolean
  1111. set_new_magstep()
  1112. {
  1113.     int new_magstep;
  1114.     Boolean changed = False;
  1115.     Arg args[20];
  1116.     Cardinal num_args;
  1117.     float xdpi, ydpi;
  1118.  
  1119.     new_magstep = app_res.magstep;
  1120.     /* If magstep changed, stop interpreter and setup for new dpi. */
  1121.     if (new_magstep != current_magstep) {
  1122.     GhostviewDisableInterpreter(page);
  1123.     XawFormDoLayout(form, False);
  1124.     reset_size_hints();
  1125.     reset_scroll_bars();
  1126.     break_chains();
  1127.     changed = True;
  1128.     xdpi = default_xdpi;
  1129.     ydpi = default_ydpi;
  1130.     magnify(&xdpi, new_magstep);
  1131.     magnify(&ydpi, new_magstep);
  1132.                             num_args = 0;
  1133.     XtSetFloatArg(args[num_args], XtNxdpi, xdpi);    num_args++;
  1134.     XtSetFloatArg(args[num_args], XtNydpi, ydpi);    num_args++;
  1135.     XtSetValues(page, args, num_args);
  1136.  
  1137.     XtSetArg(args[0], XtNleftBitmap, None);
  1138.     XtSetValues(magstepentry[current_magstep - app_res.minimum_magstep],
  1139.             args, ONE);
  1140.     current_magstep = new_magstep;
  1141.     }
  1142.     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
  1143.     XtSetValues(magstepentry[current_magstep - app_res.minimum_magstep],
  1144.         args, ONE);
  1145.  
  1146.     return changed;
  1147. }
  1148.  
  1149. /* Set new orientation */
  1150. Boolean
  1151. set_new_orientation(number)
  1152.     int number;
  1153. {
  1154.     Boolean changed = False;
  1155.     Boolean from_doc = False;
  1156.     Arg args[1];
  1157.     XtPageOrientation new_orientation;
  1158.  
  1159.     if (app_res.force_orientation) {
  1160.     new_orientation = app_res.orientation;
  1161.     } else {
  1162.     if (doc) {
  1163.         if (toc_text && doc->pages[number].orientation != NONE) {
  1164.         new_orientation = xorient(doc->pages[number].orientation);
  1165.         from_doc = True;
  1166.         } else if (doc->default_page_orientation != NONE) {
  1167.         new_orientation = xorient(doc->default_page_orientation);
  1168.         from_doc = True;
  1169.         } else if (doc->orientation != NONE) {
  1170.         new_orientation = xorient(doc->orientation);
  1171.         from_doc = True;
  1172.         } else {
  1173.         new_orientation = app_res.orientation;
  1174.         }
  1175.     } else {
  1176.         new_orientation = app_res.orientation;
  1177.     }
  1178.     }
  1179.  
  1180.     /* If orientation changed,
  1181.      * stop interpreter and setup for new orientation. */
  1182.     if (new_orientation != current_orientation) {
  1183.     GhostviewDisableInterpreter(page);
  1184.     XawFormDoLayout(form, False);
  1185.     reset_size_hints();
  1186.     reset_scroll_bars();
  1187.     break_chains();
  1188.     changed = True;
  1189.     XtSetArg(args[0], XtNorientation, new_orientation);
  1190.     XtSetValues(page, args, ONE);
  1191.     XtSetArg(args[0], XtNleftBitmap, None);
  1192.     if (current_orientation == XtPageOrientationPortrait) 
  1193.         XtSetValues(portraitbutton, args, ONE);
  1194.     else if (current_orientation == XtPageOrientationLandscape)
  1195.             XtSetValues(landscapebutton, args, ONE);
  1196.         else if (current_orientation == XtPageOrientationUpsideDown)
  1197.             XtSetValues(upsidedownbutton, args, ONE);
  1198.         else if (current_orientation == XtPageOrientationSeascape)
  1199.             XtSetValues(seascapebutton, args, ONE);
  1200.     current_orientation = new_orientation;
  1201.     }
  1202.  
  1203.     /* mark forced orientation with tie fighter. ("Use the force, Luke") */
  1204.     if (app_res.force_orientation) {
  1205.     XtSetArg(args[0], XtNleftBitmap, tie_fighter_bitmap);
  1206.     } else if (from_doc) {
  1207.     XtSetArg(args[0], XtNleftBitmap, menu16_bitmap);
  1208.     } else {
  1209.     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
  1210.     }
  1211.     if (current_orientation == XtPageOrientationPortrait) 
  1212.     XtSetValues(portraitbutton, args, ONE);
  1213.     else if (current_orientation == XtPageOrientationLandscape)
  1214.     XtSetValues(landscapebutton, args, ONE);
  1215.     else if (current_orientation == XtPageOrientationUpsideDown)
  1216.     XtSetValues(upsidedownbutton, args, ONE);
  1217.     else if (current_orientation == XtPageOrientationSeascape)
  1218.     XtSetValues(seascapebutton, args, ONE);
  1219.     
  1220.     return changed;
  1221. }
  1222.  
  1223. /* Set new pagemedia */
  1224. Boolean
  1225. set_new_pagemedia(number)
  1226.     int number;
  1227. {
  1228.     int new_pagemedia;
  1229.     int new_llx;
  1230.     int new_lly;
  1231.     int new_urx;
  1232.     int new_ury;
  1233.     Boolean changed = False;
  1234.     Boolean from_doc = False;
  1235.     Arg args[4];
  1236.  
  1237.     if (force_document_media) {
  1238.     new_pagemedia = document_media;
  1239.     } else if (app_res.force_pagemedia) {
  1240.     new_pagemedia = default_pagemedia;
  1241.     } else {
  1242.     if (doc) {
  1243.         if (toc_text && doc->pages[number].media != NULL) {
  1244.         new_pagemedia = doc->pages[number].media - doc->media;
  1245.         from_doc = True;
  1246.         } else if (doc->default_page_media != NULL) {
  1247.         new_pagemedia = doc->default_page_media - doc->media;
  1248.         from_doc = True;
  1249.         } else {
  1250.         new_pagemedia = default_pagemedia;
  1251.         }
  1252.     } else {
  1253.         new_pagemedia = default_pagemedia;
  1254.     }
  1255.     }
  1256.  
  1257.     /* If pagemedia changed, remove the old marker. */
  1258.     if (new_pagemedia != current_pagemedia) {
  1259.     XtSetArg(args[0], XtNleftBitmap, None);
  1260.     if (pagemediaentry[current_pagemedia])
  1261.         XtSetValues(pagemediaentry[current_pagemedia], args, ONE);
  1262.     else
  1263.         XtSetValues(pagemediaentry[current_pagemedia-1], args, ONE);
  1264.  
  1265.     current_pagemedia = new_pagemedia;
  1266.     }
  1267.  
  1268.     /* mark forced page media with tie fighter. ("Use the force, Luke") */
  1269.     if (force_document_media || app_res.force_pagemedia) {
  1270.     XtSetArg(args[0], XtNleftBitmap, tie_fighter_bitmap);
  1271.     } else if (from_doc) {
  1272.     XtSetArg(args[0], XtNleftBitmap, menu16_bitmap);
  1273.     } else {
  1274.     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
  1275.     }
  1276.     if (pagemediaentry[current_pagemedia])
  1277.     XtSetValues(pagemediaentry[current_pagemedia], args, ONE);
  1278.     else
  1279.     XtSetValues(pagemediaentry[current_pagemedia-1], args, ONE);
  1280.  
  1281.     /* Compute bounding box */
  1282.     if (!force_document_media && !app_res.force_pagemedia &&
  1283.     doc && doc->epsf &&
  1284.     /* Ignore malformed bounding boxes */
  1285.     (doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
  1286.     (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
  1287.     new_llx = doc->boundingbox[LLX];
  1288.     new_lly = doc->boundingbox[LLY];
  1289.     new_urx = doc->boundingbox[URX];
  1290.     new_ury = doc->boundingbox[URY];
  1291.     } else {
  1292.     new_llx = new_lly = 0;
  1293.     if (new_pagemedia < base_papersize) {
  1294.         new_urx = doc->media[new_pagemedia].width;
  1295.         new_ury = doc->media[new_pagemedia].height;
  1296.     } else {
  1297.         new_urx = papersizes[new_pagemedia-base_papersize].width;
  1298.         new_ury = papersizes[new_pagemedia-base_papersize].height;
  1299.     }
  1300.     }
  1301.  
  1302.     /* If bounding box changed, setup for new size. */
  1303.     if ((new_llx != current_llx) || (new_lly != current_lly) ||
  1304.     (new_urx != current_urx) || (new_ury != current_ury)) {
  1305.     GhostviewDisableInterpreter(page);
  1306.     XawFormDoLayout(form, False);
  1307.     reset_size_hints();
  1308.     reset_scroll_bars();
  1309.     break_chains();
  1310.     changed = True;
  1311.     current_llx = new_llx;
  1312.     current_lly = new_lly;
  1313.     current_urx = new_urx;
  1314.     current_ury = new_ury;
  1315.     XtSetArg(args[0], XtNllx, current_llx);
  1316.     XtSetArg(args[1], XtNlly, current_lly);
  1317.     XtSetArg(args[2], XtNurx, current_urx);
  1318.     XtSetArg(args[3], XtNury, current_ury);
  1319.     XtSetValues(page, args, FOUR);
  1320.     }
  1321.  
  1322.     return changed;
  1323. }
  1324.  
  1325. static Boolean
  1326. same_document_media()
  1327. {
  1328.     int i;
  1329.  
  1330.     if (olddoc == NULL && doc == NULL) return True;
  1331.     if (olddoc == NULL || doc == NULL) return False;
  1332.     if (olddoc->nummedia != doc->nummedia) return False;
  1333.     for (i = 0; i < doc->nummedia; i++)
  1334.     if (strcmp(olddoc->media[i].name, doc->media[i].name)) return False;
  1335.     return True;
  1336. }
  1337.  
  1338. void
  1339. build_pagemedia_menu()
  1340. {
  1341.     Arg args[20];
  1342.     Cardinal num_args;
  1343.     Widget w;
  1344.     int i;
  1345.  
  1346.     if (pagemediamenu && same_document_media()) return;
  1347.     if (pagemediamenu) XtDestroyWidget(pagemediamenu);
  1348.     force_document_media = False;
  1349.  
  1350.                             num_args = 0;
  1351.     XtSetArg(args[num_args], XtNcolormap, cmap);    num_args++;
  1352.     if (special_cmap) {
  1353.     XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  1354.     }
  1355.     pagemediamenu = XtCreatePopupShell("menu", simpleMenuWidgetClass,
  1356.                        pagemediabutton, args, num_args);
  1357.  
  1358.     /* Build the Page Media menu */
  1359.     /* the Page media menu has two parts.
  1360.      *  - the document defined page medias
  1361.      *  - the standard page media defined from Adobe's PPD
  1362.      */
  1363.     base_papersize = 0;
  1364.     if (doc) base_papersize = doc->nummedia;
  1365.     for (i = 0; papersizes[i].name; i++) {}    /* Count the standard entries */
  1366.     i += base_papersize;
  1367.     pagemediaentry = (Widget *) XtMalloc(i * sizeof(Widget));
  1368.  
  1369.     if (doc && doc->nummedia) {
  1370.     for (i = 0; i < doc->nummedia; i++) {
  1371.                                 num_args = 0;
  1372.         if (special_cmap) {
  1373.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  1374.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  1375.         }
  1376.         XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
  1377.         pagemediaentry[i] = XtCreateManagedWidget(doc->media[i].name,
  1378.                 smeBSBObjectClass, pagemediamenu,
  1379.                 args, num_args);
  1380.         XtAddCallback(pagemediaentry[i], XtNcallback,
  1381.               set_pagemedia, (XtPointer)i);
  1382.     }
  1383.  
  1384.                             num_args = 0;
  1385.     if (special_cmap) {
  1386.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  1387.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  1388.     }
  1389.     w = XtCreateManagedWidget("line", smeLineObjectClass, pagemediamenu,
  1390.                   args, num_args);
  1391.     }
  1392.  
  1393.     for (i = 0; papersizes[i].name; i++) {
  1394.     pagemediaentry[i+base_papersize] = NULL;
  1395.     if (i > 0) {
  1396.         /* Skip over same paper size with small imageable area */
  1397.         if ((papersizes[i].width == papersizes[i-1].width) &&
  1398.         (papersizes[i].height == papersizes[i-1].height)) {
  1399.         continue;
  1400.         }
  1401.     }
  1402.                             num_args = 0;
  1403.     if (special_cmap) {
  1404.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  1405.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  1406.     }
  1407.     XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
  1408.     pagemediaentry[i+base_papersize] = XtCreateManagedWidget(
  1409.                         papersizes[i].name,
  1410.                         smeBSBObjectClass, pagemediamenu,
  1411.                         args, num_args);
  1412.     XtAddCallback(pagemediaentry[i+base_papersize], XtNcallback,
  1413.               set_pagemedia, (XtPointer)(i+base_papersize));
  1414.     }
  1415. }
  1416.  
  1417. Widget
  1418. build_label_menu(parent, name, label, bitmap)
  1419.     Widget parent;
  1420.     String name, label;
  1421.     Pixmap bitmap;
  1422. {
  1423.     Arg args[20];
  1424.     Cardinal num_args;
  1425.     Widget menu, entry;
  1426.                                 num_args = 0;
  1427.     XtSetArg(args[num_args], XtNcolormap, cmap);        num_args++;
  1428.     if (special_cmap) {
  1429.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  1430.     }
  1431.     menu = XtCreatePopupShell("menu", simpleMenuWidgetClass,
  1432.                   parent, args, num_args);
  1433.  
  1434.                                 num_args = 0;
  1435.     if (special_cmap) {
  1436.         XtSetArg(args[num_args], XtNforeground, black);    num_args++;
  1437.         XtSetArg(args[num_args], XtNbackground, white);    num_args++;
  1438.     }
  1439.     XtSetArg(args[num_args], XtNlabel, label);        num_args++;
  1440.     if (bitmap) {
  1441.         XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
  1442.         XtSetArg(args[num_args], XtNleftBitmap, bitmap);    num_args++;
  1443.     }
  1444.     entry = XtCreateManagedWidget(name, smeBSBObjectClass,
  1445.                       menu, args, num_args);
  1446.     return menu;
  1447. }
  1448.  
  1449. void
  1450. new_file(number)
  1451.     int number;
  1452. {
  1453.     Boolean layout_changed = False;
  1454.  
  1455.     if (setup_ghostview()) layout_changed = True;
  1456.  
  1457.     /* Coerce page number to fall in range */
  1458.     if (toc_text) {
  1459.     if (number >= doc->numpages) number = doc->numpages - 1;
  1460.     if (number < 0) number = 0;
  1461.     }
  1462.  
  1463.     if (set_new_orientation(number)) layout_changed = True;
  1464.     if (set_new_pagemedia(number)) layout_changed = True;
  1465.     if (layout_changed) layout_ghostview();
  1466. }
  1467.  
  1468. /* Catch X errors die gracefully if one occurs */
  1469. int
  1470. catch_Xerror(dpy, err)
  1471.     Display *dpy;
  1472.     XErrorEvent *err;
  1473. {
  1474.     if (err->error_code == BadImplementation) {
  1475.     old_Xerror(dpy, err);
  1476.     return 0;
  1477.     }
  1478.     if (dying) return 0;
  1479.     dying = True;
  1480.     bomb = *err;
  1481.     XtDestroyWidget(toplevel);
  1482.     return 0;
  1483. }
  1484.